﻿//---------------------------------------------------------------------------
// <summary>
// Represents the string body that gets sent when IPFS does a postback
// </summary>
//---------------------------------------------------------------------------

namespace InfoPathExtractionRules
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;

    /// <summary>
    /// Enumerates different formats to represent the string body of an IPFS postback.
    /// </summary>
    public enum Format
    {
        /// <summary>
        /// List of event logs.
        /// </summary>
        EventLogList,

        /// <summary>
        /// Entire postback body that would be sent over the wire.
        /// </summary>
        FormsServicesPostBackBody
    }

    /// <summary>
    /// Represents the string body that gets sent when IPFS does a postback.
    /// </summary>
    public class FormsServicesPostBackBody
    {
        /// <summary>
        /// List of event logs.
        /// </summary>
        private List<EventLog> eventLogs = new List<EventLog>();

        /// <summary>
        /// Initializes a new instance of the FormsServicesPostBackBody class.
        /// Constructs an object using an IPFS postback body string.
        /// </summary>
        /// <param name="body">String from an IPFS postback body.</param>
        public FormsServicesPostBackBody(string body)
        {
            this.InitWithFormsServicesPostBackBody(body);
        }

        /// <summary>
        /// Initializes a new instance of the FormsServicesPostBackBody class.
        /// Constructs an IpfsPostBackBody using a particular
        /// input format for interpreting the string.
        /// </summary>
        /// <param name="input">String used to construct the event logs.</param>
        /// <param name="method">Format of the input string.</param>
        public FormsServicesPostBackBody(string input, Format method)
        {
            switch (method)
            {
                case Format.EventLogList:
                    this.InitWithEventLogList(input);
                    break;
                case Format.FormsServicesPostBackBody:
                    this.InitWithFormsServicesPostBackBody(input);
                    break;
            }
        }

        /// <summary>
        /// Substitutes the dynamic currentFormData that was extracted
        /// from an earlier request.
        /// </summary>
        /// <param name="currentFormData">List of currentFormData.</param>
        public void SubstituteCurrentFormData(System.Collections.ObjectModel.Collection<CurrentFormData> currentFormData)
        {
            for (int i = 0; i < this.eventLogs.Count; i++)
            {
                EventLog log = this.eventLogs[i];
                CurrentFormData data = currentFormData[i];
                log.EventLogInfo.EditingSessionId = data.EditingSessionId;
                log.EventLogInfo.SolutionId = data.SolutionId;
                log.EventLogInfo.Canary = data.Canary;
                log.EventLogInfo.SessionState = data.SessionState;
            }
        }

        /// <summary>
        /// Returns the string that would be in a IPFS postback body.
        /// </summary>
        /// <returns>IPFS postback body.</returns>
        public override string ToString()
        {
            return this.ToFormsServicesPostBackBodyString();
        }

        /// <summary>
        /// String representation of the event logs using the given format.
        /// </summary>
        /// <param name="format">Format to use when creating the output string.</param>
        /// <returns>String representation of the event logs in the specified format.</returns>
        public string ToString(Format format)
        {
            string output = null;
            switch (format)
            {
                case Format.EventLogList:
                    output = this.ToEventLogListString();
                    break;
                case Format.FormsServicesPostBackBody:
                    output = this.ToFormsServicesPostBackBodyString();
                    break;
            }

            return output;
        }

        /// <summary>
        /// Returns a string containg a list of event logs separated by newlines.
        /// </summary>
        /// <returns>List of event logs.</returns>
        public string ToEventLogListString()
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < this.eventLogs.Count; i++)
            {
                EventLog log = this.eventLogs[i];
                builder.Append(log.ToString());
                if (i < this.eventLogs.Count - 1)
                {
                    builder.AppendLine();
                }
            }

            return builder.ToString();
        }

        /// <summary>
        /// Returns the string that would be in a IPFS postback body.
        /// </summary>
        /// <returns>IPFS postback body.</returns>
        public string ToFormsServicesPostBackBodyString()
        {
            StringBuilder builder = new StringBuilder();

            builder.Append(this.eventLogs.Count);
            builder.AppendLine();

            foreach (EventLog log in this.eventLogs)
            {
                string formID = log.EventLogInfo.FormId;
                string logString = log.ToString();

                builder.Append(formID.Length);
                builder.AppendLine();

                builder.Append(formID);
                builder.Append(logString.Length);
                builder.AppendLine();

                builder.Append(logString);
            }

            return builder.ToString();
        }

        /// <summary>
        /// Initializes this object's list of event logs using
        /// a string body which would go over the wire when
        /// an IPFS postback occurs.
        /// </summary>
        /// <param name="body">String from an IPFS postback body.</param>
        private void InitWithFormsServicesPostBackBody(string body)
        {
            StringReader reader = new StringReader(body);
            string curr;

            curr = reader.ReadLine();
            int numEventLogs = int.Parse(curr, System.Globalization.NumberFormatInfo.InvariantInfo);

            // Parse the event logs
            for (int i = 0; i < numEventLogs; i++)
            {
                curr = reader.ReadLine();
                int formIDLength = int.Parse(curr, System.Globalization.NumberFormatInfo.InvariantInfo);

                char[] buffer = new char[formIDLength];
                reader.Read(buffer, 0, formIDLength);

                curr = reader.ReadLine();
                int eventLogLength = int.Parse(curr, System.Globalization.NumberFormatInfo.InvariantInfo);

                buffer = new char[eventLogLength];
                reader.Read(buffer, 0, eventLogLength);
                string eventLog = new string(buffer);

                EventLog log = new EventLog(eventLog);
                this.eventLogs.Add(log);
            }
        }

        /// <summary>
        /// Initializes this objects list of event logs using
        /// a string containing a list of event logs separated
        /// by newlines.
        /// </summary>
        /// <param name="eventLogList">List of event logs separated by newlines.</param>
        private void InitWithEventLogList(string eventLogList)
        {
            StringReader reader = new StringReader(eventLogList);
            string currLine;
            while (true)
            {
                currLine = reader.ReadLine();
                if (String.IsNullOrEmpty(currLine))
                {
                    break;
                }

                EventLog log = new EventLog(currLine);
                this.eventLogs.Add(log);
            }
        }
    }
}
